import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler  # 仅用于特征标准化

# 1.欧氏距离计算
def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1 - x2) ** 2))

# 2.KNN预测函数
def knn_predict(x_test, X_train, y_train, k=5):  # 调整k为5（更适合Wine数据集）
    distances = [euclidean_distance(x_test, x) for x in X_train]
    k_indices = np.argsort(distances)[:k]
    k_labels = [y_train[i] for i in k_indices]
    return max(set(k_labels), key=k_labels.count)

# 3.加载并预处理Wine数据
if __name__ == "__main__":
    wine_cols = ["class", "alcohol", "malic_acid", "ash", "alcalinity_of_ash",
                 "magnesium", "total_phenols", "flavanoids", "nonflavanoid_phenols",
                 "proanthocyanins", "color_intensity", "hue", "od280/od315", "proline"]
    wine_data = pd.read_csv("wine.data", header=None, names=wine_cols)
    wine_data["class"] = wine_data["class"] - 1
    X = wine_data.iloc[:, 1:].values
    y = wine_data.iloc[:, 0].values

    # 特征标准化
    scaler = StandardScaler()
    X_scaled = scaler.fit_transform(X)

    # 划分训练集（70%）和测试集（30%），固定随机种子
    np.random.seed(42)
    indices = np.random.permutation(len(X_scaled))
    train_size = int(len(X_scaled) * 0.7)
    X_train, X_test = X_scaled[indices[:train_size]], X_scaled[indices[train_size:]]
    y_train, y_test = y[indices[:train_size]], y[indices[train_size:]]

    # 批量预测测试集
    y_pred = [knn_predict(x, X_train, y_train, k=5) for x in X_test]
    accuracy = np.sum(y_pred == y_test) / len(y_test)
    print(f"KNN分类准确率（k=5，特征标准化）：{accuracy:.2%}")

    # 输出前5条测试样本结果
    print("\n前5条测试样本预测结果：")
    for i in range(5):
        print(f"真实类别：{y_test[i]} | 预测类别：{y_pred[i]}")